package midend.IR_Value;

import midend.IR_Instruction.Instruction;
import midend.IR_Type.IR_Const;
import midend.IR_Type.IR_Type;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

// bb base block
public class IR_BaseBlock extends IR_Value{
    private static int bbcounter = 0;
    private int bbId;
    private StringBuilder s;
    private String bb_Name;
    private LinkedList<Instruction> Instruction_List;
    private IR_FuncBlock funcBlock;
    private List<IR_Value> preList = new ArrayList<>();
    private List<IR_Value> nextList = new ArrayList<>();

    private List<IR_BaseBlock> preBlock = new ArrayList<>();
    private List<IR_BaseBlock> nextBlock = new ArrayList<>();

    private IR_BaseBlock parentBlock;
    private ArrayList<IR_BaseBlock> childBlock = new ArrayList<>();

    int dep = 0;

    public IR_BaseBlock(String name,IR_FuncBlock func){
        bb_Name = name;
        s = new StringBuilder();
        this.funcBlock = func;
        this.bbId = bbcounter++;
        this.Instruction_List = new LinkedList<>();
    }
    public IR_BaseBlock(String name,int dep){
        bb_Name = name;
        this.dep = dep;
        s = new StringBuilder();
        this.bbId = bbcounter++;
        this.Instruction_List = new LinkedList<>();
    }
    public IR_BaseBlock(String name){
        bb_Name = name;
        s = new StringBuilder();
        this.bbId = bbcounter++;
        this.Instruction_List = new LinkedList<>();
    }
    public void set_FuncBlock(IR_FuncBlock funcBlock) {
        this.funcBlock = funcBlock;
    }

    public StringBuilder get_s() {
        return s;
    }

    public LinkedList<Instruction> get_Instruction_List() {
        return Instruction_List;
    }

    public void setInstruction_List(LinkedList<Instruction> instruction_List) {
        Instruction_List = instruction_List;
    }

    public IR_FuncBlock get_FuncBlock(){
        return this.funcBlock;
    }

    public List<IR_Value> get_preList() {
        return preList;
    }

    public List<IR_Value> get_nextList() {
        return nextList;
    }

    public void add_preList(IR_BaseBlock tmpbb){
        this.preList.add(tmpbb);
    }

    public void add_nextList(IR_BaseBlock tmpbb){
        this.nextList.add(tmpbb);
    }
    public void add_InstructionList(Instruction tmpinst){
        this.Instruction_List.add(tmpinst);
    }
    public void add_InstructionList_at_Start(Instruction tmpinst){
        this.Instruction_List.add(0,tmpinst);
    }
    public void appendln(String s){
        this.s.append("  ").append(s).append("\n");
    }
    public void appendln(String s,int align){
        this.s.append("  ").append(s).append(", align ").append(align).append("\n");
    }
    @Override
    public String get_ValueName() {
        return bb_Name + bbId;
    }

    public String getName() {
        return bb_Name;
    }
    @Override
    public IR_Type get_Type() {
        return null;
    }

    @Override
    public int get_Const_Type() {
        return IR_Const.IR_BasicBlock;
    }

    //需要在实例化之前调用 ，需要是静态的
    public static IR_BaseBlock add_Baseblock(IR_FuncBlock func,String label,int dep){
        //在函数块 里面添加基本块
        IR_BaseBlock newbb = new IR_BaseBlock(label,dep + 1);
        func.addbb(newbb);
        newbb.set_FuncBlock(func);
        return newbb;
    }

    public static IR_BaseBlock add_Baseblock(IR_FuncBlock func,String label){
        //在函数块 里面添加基本块
        IR_BaseBlock newbb = new IR_BaseBlock(label);
        func.addbb(newbb);
        newbb.set_FuncBlock(func);
        return newbb;
    }
    public int getLoopDep(){
        return dep;
    }

    public void setPreBlock(ArrayList<IR_BaseBlock> preBlock){
        this.preBlock = preBlock;
    }

    public void setNextBlock(ArrayList<IR_BaseBlock> nextBlock){
        this.nextBlock = nextBlock;
    }

    public void add_PreBlock(IR_BaseBlock tmpbb){
        this.preBlock.add(tmpbb);
    }

    public void add_NextBlock(IR_BaseBlock tmpbb){
        this.nextBlock.add(tmpbb);
    }

    public List<IR_BaseBlock> getPreBlock() {
        return this.preBlock;
    }

    public List<IR_BaseBlock> getNextBlock() {
        return this.nextBlock;
    }

    public void setS(){
        s = new StringBuilder();
    }

    @Override
    public String toString() {
        return get_ValueName();
    }

    public void setParentBlock(IR_BaseBlock parent){
        this.parentBlock = parent;
    }

    public void setChildBlock(ArrayList<IR_BaseBlock> childBlock){
        this.childBlock = childBlock;
    }

    public void addChildBlock(IR_BaseBlock onechild){
        for (IR_BaseBlock ch : childBlock){
            if (ch.get_ValueName().equals(onechild.get_ValueName())){
                return;
            }
        }
        this.childBlock.add(onechild);
    }

    public ArrayList<IR_BaseBlock> getChildBlock()
    {
        return this.childBlock;
    }

}
